package com.ys.web.user.login;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ys.base.BaseConstants;
import com.ys.base.EnumType;
import com.ys.utils.base.http.McodeHandler;
import com.ys.utils.base.j2se.JsonUtil;
import com.ys.utils.base.j2se.MapHandler;
import com.ys.utils.base.j2se.StringHandler;
import com.ys.utils.base.secret.MD5;
import com.ys.utils.help.UserUtils;
import com.ys.utils.redis.Redis;
import com.ys.utils.redis.key.UserKey;
import com.ys.utils.spring.config.SystemError;
import com.ys.utils.spring.properties.Config;
import com.ys.web.user.friends.mapper.UserGroupMapper;
import com.ys.web.user.info.RealEntity;
import com.ys.web.user.info.UserInfoMapper;
import com.ys.web.ws.manager.ChatObjectManager;
import io.vertx.core.http.ServerWebSocket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

/**
 * Description
 * Created by 王伟
 * Date create on 14:26 2019/11/19.
 */
@Service
public class LoginService {
    @Autowired
    private LoginDao loginDao;
    @Autowired
    private UserInfoMapper userInfoMapper;

    @Autowired
    private UserGroupMapper userGroupMapper;

    public Map<String, String> uToken = new HashMap<>();

    /**
     * 登录令牌过期时间30天
     */
    private final int tokenTimeOut = 15 * 24 * 60 * 60;
    /**
     * 用户缓存过期时间3天
     */
    public final static int loginInfoTimeOut = 15 * 24 * 60 * 60;
    /**
     * 手机验证码缓存过期时间5分钟
     */
    private final int bindMobileCodeTimeOut = 5 * 60;

    public LoginInfo selectByPrimaryKey(int id) {
        return new LoginInfo();
    }

    /**
     * 查询登录信息
     *
     * @param userId 用户ID
     * @return 登录信息
     */
    public LoginInfo infoById(String userId) {
        return loginDao.infoById(StringHandler.getLong(userId));
    }

    /**
     * 查询登录信息
     *
     * @param userId 用户ID
     * @return 登录信息
     */
    @SuppressWarnings("rawtypes")
    public LoginInfo infoByUid(String userId) {
        //缓存中登录信息没有失效 直接返回
        String userKey = UserKey.userInfoByUid(userId);
        Map loginCache = Redis.hash.hgetall(userKey);
        LoginInfo loginInfo = null;
        if (StringHandler.isNotEmpty(loginCache) && StringHandler.isNotEmpty(loginCache.get("id"))) {
            loginInfo = JsonUtil.mapToBean(loginCache, LoginInfo.class);
            loginInfo.checkNull();
            return loginInfo;
        }
        //缓存已经失效 查询数据库 将登录信息缓存到redis
        loginInfo = loginDao.infoById(StringHandler.getLong(userId));
        if (null != loginInfo) {
            Map<String, Object> initCache = (JSONObject) JSON.toJSON(loginInfo);
            Redis.hash.hmset(userKey, MapHandler.obj2StrNotNull(initCache), loginInfoTimeOut);
            loginInfo.checkNull();
        }
        return loginInfo;
    }

    /**
     * 功能：根据unid查询登录信息
     *
     * @param unionId 微信unid
     * @return
     */
    public LoginInfo info(String unionId) {
        //查询缓存中 unid 和 userId 的映射关系 查询到了 通过用户ID查询登录信息
        String unidKey = UserKey.uidByUnion(unionId);
        String userId = Redis.str.getAndExpire(unidKey, tokenTimeOut);
        LoginInfo loginInfo = null;
        if (StringHandler.isNotEmpty(userId)) {
            return infoByUid(userId);
        }
        //没有查询到 通过unid查询用户信息 并缓存
        loginInfo = loginDao.infoByUnId(unionId);
        if (StringHandler.isNotEmpty(loginInfo)) {
            String userKey = UserKey.userInfoByUid(loginInfo.getId());
            Redis.str.set(unidKey, StringHandler.getString(loginInfo.getId()), tokenTimeOut);
            Redis.hash.hmset(userKey, MapHandler.obj2StrNotNull(JsonUtil.beanToMap(loginInfo)), loginInfoTimeOut);
            loginInfo.checkNull();
        }
        return loginInfo;
    }

    /**
     * 功能：根据phone查询登录信息
     *
     * @param phone phone
     * @return
     */
    public LoginInfo infoByPhone(String phone) {
        //查询缓存中 phone 和 userId 的映射关系 查询到了 通过用户ID查询登录信息
        String phoneKey = UserKey.uidByPhone(phone);
        String userId = Redis.str.getAndExpire(phoneKey, tokenTimeOut);
        if (StringHandler.isNotEmpty(userId)) {
            return infoByUid(userId);
        }
        //没有查询到 通过phone查询用户信息 并缓存
        LoginInfo loginInfo = loginDao.infoByPhone(phone);
        if (StringHandler.isNotEmpty(loginInfo)) {
            String userKey = UserKey.userInfoByUid(loginInfo.getId());
            Redis.str.set(phoneKey, StringHandler.getString(loginInfo.getId()), tokenTimeOut);
            Redis.hash.hmset(userKey, MapHandler.obj2StrNotNull(JsonUtil.beanToMap(loginInfo)), loginInfoTimeOut);
            loginInfo.checkNull();
        }
        return loginInfo;
    }

    /**
     * 功能：根据phone查询登录信息
     *
     * @param appleId
     * @return
     */
    public LoginInfo infoByApple(String appleId) {
        //查询缓存中 appleId 和 userId 的映射关系 查询到了 通过用户ID查询登录信息
        String key = UserKey.uidByApple(appleId);
        String userId = Redis.str.getAndExpire(key, tokenTimeOut);
        if (StringHandler.isNotEmpty(userId)) {
            return infoByUid(userId);
        }
        //没有查询到 通过phone查询用户信息 并缓存
        LoginInfo loginInfo = loginDao.infoByApple(appleId);
        if (StringHandler.isNotEmpty(loginInfo)) {
            String userKey = UserKey.userInfoByUid(loginInfo.getId());
            Redis.str.set(key, StringHandler.getString(loginInfo.getId()), tokenTimeOut);
            Redis.hash.hmset(userKey, MapHandler.obj2StrNotNull(JsonUtil.beanToMap(loginInfo)), loginInfoTimeOut);
            loginInfo.checkNull();
        }
        return loginInfo;
    }

    /**
     * 功能：添加登录信息
     *
     * @param loginInfo 登录信息
     * @return
     */
    public void add(LoginInfo loginInfo) {
        loginDao.addInfo(loginInfo);
        //初始化用户隐私设置
        loginDao.initUserPrivacyConfig(loginInfo);
    }

    /**
     * 功能:更新登录信息
     *
     * @param loginInfo 登录信息
     * @return
     */
    public void updateInfoByWx(LoginInfo loginInfo) {
        int i = loginDao.updateInfoByWx(loginInfo);
        if (i != 1) {
            SystemError.wrapBs("500", "绑定失败");
        }
        String phoneKey = UserKey.uidByPhone(loginInfo.getPhone());
        Redis.key.del(phoneKey);
        String userKey = UserKey.userInfoByUid(loginInfo.getId());
        Redis.key.del(userKey);
        String key = UserKey.uidByUnion(loginInfo.getUnionId());
        Redis.key.del(key);
    }

    public void updateInfoByPhone(LoginInfo loginInfo) {
        int i = loginDao.updateInfoByPhone(loginInfo);
        if (i != 1) {
            SystemError.wrapBs("500", "绑定失败");
        }
        String userKey = UserKey.userInfoByUid(loginInfo.getId());
        Redis.key.del(userKey);
        String phoneKey = UserKey.uidByPhone(loginInfo.getPhone());
        Redis.key.del(phoneKey);
    }

    public void updateInfoByApple(LoginInfo loginInfo) {
        int i = loginDao.updateInfoByApple(loginInfo);
        if (i != 1) {
            SystemError.wrapBs("500", "绑定失败");
        }
        String phoneKey = UserKey.uidByPhone(loginInfo.getPhone());
        Redis.key.del(phoneKey);
        String userKey = UserKey.userInfoByUid(loginInfo.getId());
        Redis.key.del(userKey);
        String key = UserKey.uidByApple(loginInfo.getAppleId());
        Redis.key.del(key);
    }

    /**
     * 添加用户黑名单
     *
     * @param userId 用户id
     */
    public int addBlack(int userId) {
        loginDao.addBlack(userId);
        return 1;
    }

    /**
     * 添加取消黑名单
     *
     * @param userId 用户id
     */
    public int cancelBlack(int userId) {
        loginDao.cancelBlack(userId);
        return 1;
    }

    /**
     * 组装登录用户信息
     *
     * @param loginInfo 登录信息
     * @return 登录用户信息
     */
    public Map<String, Object> loginUser(LoginInfo loginInfo) {
        if (StringHandler.isEmpty(loginInfo)) {
            return null;
        }
        String alias = McodeHandler.to32Radix(StringHandler.getLong(loginInfo.getId()));
        Map<String, Object> loginUser = new HashMap<>();
        loginUser.put("alias", alias);//用户别名，用于绑定消息推送
        loginUser.put("nickName", loginInfo.getNickName());
        loginUser.put("avatarUrl", loginInfo.getAvatarUrl());
        loginUser.put("havePhone", StringHandler.isNotEmpty(loginInfo.getPhone()));
        loginUser.put("haveApple", StringHandler.isNotEmpty(loginInfo.getAppleId()));
        loginUser.put("haveWx", StringHandler.isNotEmpty(loginInfo.getOpenId()));
        loginUser.put("hasPayPass", StringHandler.isNotEmpty(loginInfo.getPayPass()));
        loginUser.put("ysLevel", "未认证");
        loginUser.put("ip", StringHandler.getString(loginInfo.getIp()));
        if(StringHandler.getString(Config.pp.get("ys.user.pay.channel"),"ys").equals("ys")) {
            int userBank = userInfoMapper.getUserBankCount(loginInfo.id);
            if(StringHandler.isNotEmpty(loginInfo.getRealIdCard()) && userBank>1 && loginInfo.realIdCardUp==2) {
                loginUser.put("ysLevel", "高级认证");
            }else{
                if(StringHandler.isNotEmpty(loginInfo.getRealIdCard()) && userBank==1 && loginInfo.realIdCardUp==2)
                    loginUser.put("ysLevel", "中级认证");
                else{
                    if(StringHandler.isNotEmpty(loginInfo.getRealIdCard()) && userBank>0){
                        loginUser.put("ysLevel", "中级认证");
                    }else{
                        if(StringHandler.isNotEmpty(loginInfo.getRealIdCard())){
                            loginUser.put("ysLevel", "初级认证");
                        }
                    }
                }
            }
            loginUser.put("realName", loginInfo.getRealName());
            loginUser.put("idCard", loginInfo.getRealIdCard());
        }
        if(StringHandler.getString(Config.pp.get("ys.user.pay.channel"),"ys").equals("mb")) {
            Map<String, Object> idCard = userInfoMapper.getUserIdCord(loginInfo.getId());
            if(StringHandler.isNotEmpty(idCard)) {
                loginUser.put("realName", idCard.get("realName"));
                loginUser.put("idCard", idCard.get("realIdCard"));
            }
        }
        loginUser.put("level", loginInfo.getLevel());
        if(StringHandler.isNotEmpty(loginInfo.getPhone())){
            loginUser.put("phone", loginInfo.getPhone());
        }
        String token = MD5.md5(StringHandler.getString(loginInfo.getId() + System.currentTimeMillis()));
        String tokenKey = UserKey.uidByToken(token);
        Redis.str.set(tokenKey, StringHandler.getString(loginInfo.getId()), tokenTimeOut);
        String uidByTokenKey = UserKey.uidByToken(loginInfo.id);
        Redis.str.set(uidByTokenKey, token, tokenTimeOut);
        loginUser.put("token", token);
        loginUser.put("alipayUid", loginInfo.alipayUid);
        loginUser.put("alipayName", loginInfo.alipayName);
        uToken.put(loginInfo.getId(), token);
        //单点登录，同一用户顶掉上一设备
        ServerWebSocket serverWebSocket = ChatObjectManager.getConnectionMap().get(alias);
        if (StringHandler.isNotEmpty(serverWebSocket)) {
//            Logger.info("登录");
//            ChatObjectManager.getCurrentOnline();
            String str = UserUtils.getMessageResponseList(BaseConstants.SYSTEM_OBJECT_VALUE, null, EnumType.MessageCode.MESSAGE_LOGIN_TIP.getCode()
                    , null, LocalDateTime.now().format(DateTimeFormatter.ofPattern(BaseConstants.BASE_FORMAT)));
            serverWebSocket.writeTextMessage(str);
//            serverWebSocket.close();
        }
        return loginUser;
    }
    public Map<String, Object> userInfo(LoginInfo loginInfo,String token) {
        if (StringHandler.isEmpty(loginInfo)) {
            return null;
        }
        String alias = McodeHandler.to32Radix(StringHandler.getLong(loginInfo.getId()));
        Map<String, Object> loginUser = new HashMap<>();
        loginUser.put("alias", alias);//用户别名，用于绑定消息推送
        loginUser.put("nickName", loginInfo.getNickName());
        loginUser.put("avatarUrl", loginInfo.getAvatarUrl());
        loginUser.put("havePhone", StringHandler.isNotEmpty(loginInfo.getPhone()));
        loginUser.put("haveApple", StringHandler.isNotEmpty(loginInfo.getAppleId()));
        loginUser.put("haveWx", StringHandler.isNotEmpty(loginInfo.getOpenId()));
        loginUser.put("hasPayPass", StringHandler.isNotEmpty(loginInfo.getPayPass()));
        loginUser.put("ysLevel", "未认证");
        if(StringHandler.getString(Config.pp.get("ys.user.pay.channel"),"ys").equals("ys")) {
            int userBank = userInfoMapper.getUserBankCount(loginInfo.id);
            if(StringHandler.isNotEmpty(loginInfo.getRealIdCard()) && userBank>1 && loginInfo.realIdCardUp==2) {
                loginUser.put("ysLevel", "高级认证");
            }else{
                if(StringHandler.isNotEmpty(loginInfo.getRealIdCard()) && userBank==1 && loginInfo.realIdCardUp==2)
                    loginUser.put("ysLevel", "中级认证");
                else{
                    if(StringHandler.isNotEmpty(loginInfo.getRealIdCard()) && userBank>0){
                        loginUser.put("ysLevel", "中级认证");
                    }else{
                        if(StringHandler.isNotEmpty(loginInfo.getRealIdCard())){
                            loginUser.put("ysLevel", "初级认证");
                        }
                    }
                }
            }
            loginUser.put("realName", loginInfo.getRealName());
            loginUser.put("idCard", loginInfo.getRealIdCard());
        }
        if(StringHandler.getString(Config.pp.get("ys.user.pay.channel"),"ys").equals("mb")) {
            Map<String, Object> idCard = userInfoMapper.getUserIdCord(loginInfo.getId());
            if(StringHandler.isNotEmpty(idCard)) {
                loginUser.put("realName", idCard.get("realName"));
                loginUser.put("idCard", idCard.get("realIdCard"));
            }
        }
        loginUser.put("level", loginInfo.getLevel());
        if(StringHandler.isNotEmpty(loginInfo.getPhone())){
            loginUser.put("phone", loginInfo.getPhone());
        }
        loginUser.put("token", token);
        loginUser.put("alipayUid", loginInfo.alipayUid);
        loginUser.put("alipayName", loginInfo.alipayName);
        uToken.put(loginInfo.getId(), token);
        String uidByTokenKey = UserKey.uidByToken(loginInfo.id);
        Redis.str.set(uidByTokenKey, token, tokenTimeOut);
        return loginUser;
    }
    public String getGroupNameAndSize(String groupId) {
        return userGroupMapper.getGroupNameAndSize(groupId);
    }


    public void logout(Long uid,String token) {
        ServerWebSocket serverWebSocket = ChatObjectManager.getConnectionMap().get(McodeHandler.to32Radix(uid));
        ChatObjectManager.removeChatMapByKey(McodeHandler.to32Radix(uid));
        if (serverWebSocket != null) {
            try {
                serverWebSocket.close();
            } catch (Exception e) {

            }
        }
        //缓存中登录信息没有失效 直接返回
        String userKey = UserKey.userInfoByUid(uid);
        Redis.key.del(userKey);
        //删除缓存token
        String tokenKye = UserKey.uidByToken(token);
        Redis.key.del(tokenKye);
        //删除缓存uid
        String uidBuyTokenKye = UserKey.uidByToken(uid);
        Redis.key.del(uidBuyTokenKye);
        //删除缓存serverWebSocket的id值
        Redis.hash.delHash(UserKey.jPushRelationIdKey(),StringHandler.getString(uid));
    }

    public int del(LoginInfo loginInfo) {
        return loginDao.del(loginInfo);
    }

    public int updatePassWord(LoginInfo loginInfo) {
        int i = loginDao.updatePassWord(loginInfo);
        if (i == 1) {
            String userKey = UserKey.userInfoByUid(loginInfo.getId());
            Redis.key.del(userKey);
        }
        return i;
    }

    public int updatePayPassWord(LoginInfo loginInfo) {
        int i = loginDao.updatePayPassWord(loginInfo);
        if (i == 1) {
            String userKey = UserKey.userInfoByUid(loginInfo.getId());
            Redis.key.del(userKey);
        }
        return i;
    }

    public void cancel(Long uid) {
        loginDao.cancel(uid);
    }

    public void updateLocalInfoById(Long uid) {
        loginDao.updateLocalInfoById(uid);
    }

    public void delUserBankInfo(Long uid) {
        loginDao.delUserBankInfo(uid);
    }
    public void delUserBankHjzfInfo(Long uid) {
        loginDao.delUserBankHjzfInfo(uid);
    }


    public RealEntity getOpenAccountCountByCardNo(String idCard) {
        return loginDao.getOpenAccountCountByCardNo(idCard);
    }

    public Map<String, Object> getUserByUserId(String uid) {
        return loginDao.getUserByUserId(uid);
    }

    public void insertEntity(String uid, Object realName, Object card,Object phone) {
        loginDao.insertEntity(uid, realName, card,phone);
    }

    public int updateIdcard(String uid, String realName, String idCard, String phone) {
       return loginDao.updateIdcard(uid, realName, idCard,phone);
    }

    public LoginInfo getNeedValidateUser(String value, String type) {
        return loginDao.LoginInfoLocal(value, type);
    }

    /**
     * @author 但何非
     * @dateTime 2023/1/8 20:19
     * @param loginInfo:
     * @return int
     * @Description:修改用户ip
     */
    public int updateUserIp(LoginInfo loginInfo) {
        return loginDao.updateUserIp(loginInfo);
    }
}
